package pl.edu.romanow.model

import collection.mutable.LinkedHashSet
import collection.JavaConversions._
import pl.edu.romanow.util.AppException
import GraphHelper._
import Database._
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph
import java.util.concurrent.TimeUnit
import net.liftweb.common.{Loggable, Full, Box, Empty}
import com.tinkerpop.gremlin.scala.GremlinScalaPipeline
import com.tinkerpop.blueprints.pgm.{Edge, TransactionalGraph, IndexableGraph, Vertex}

/**
 * Created by IntelliJ IDEA.
 * User: jar
 * Date: 06.04.12
 * Time: 21:26
 * To change this template use File | Settings | File Templates.
 */


object GraphType {
  type MGraph = TransactionalGraph with IndexableGraph
}

case class ConnectionManager(var db: GraphType.MGraph) extends Loggable {

  Runtime.getRuntime.addShutdownHook(new Thread() {
    override def run() {
      val old_db = db;
      db = null

      TimeUnit.MILLISECONDS.sleep(100)

      old_db.shutdown()
      logger.info("Database closed.")
    }
  })

  val startPoint = {
    val it = db.getVertices.iterator()

    var search = true
    var sp: Vertex = null
    while (it.hasNext && search) {
      sp = it.next()
      if (sp.getProperty("start") == "true") {
        search = false
      }
    }
    if (sp == null) {
      db.addVertex(null)
      sp = db.addVertex(null)
    }
    sp \("start", "true") \("StartId", "0")
  }
  val thrash = {
    val it = db.getVertices.iterator()

    var search = true
    var sp: Vertex = null
    while (it.hasNext && search) {
      sp = it.next()
      if (sp.getProperty("thrash") == "true") {
        search = false
      }
    }
    if (sp == null) {
      db.addVertex(null)
      sp = db.addVertex(null) \("thrash", "true")
    }
    sp
  }


  def free() = db.shutdown();

  def createV(source: String, id: String): Vertex = {
    val v = db.addVertex(source + ":" + id + System.nanoTime()) \(source + "Id", id)
    createEdge(startPoint, v, source + ":" + id)
    v
  }

  /**
   * creates edge out --label--> in
   * @param out
   * @param in
   * @param label
   * @return
   */
  def createEdge(out: Vertex, in: Vertex, label: String) = {
    G(out).outE("label").filter(_.getInVertex != in).toList.toList match {
      case head :: _ => head
      case _ => db.addEdge(out.getId + label + in.getId, out, in, label)
    }

  }


  def findById(source: String, id: String): Box[Vertex] = {
    G(startPoint).out(source + ":" + id).toList.toList match {
      case s :: _ => Full(s)
      case Nil => Empty
    }
  }

  def findEdgeByVId(source: String, id: String): Box[Edge] = {
    G(startPoint).outE(source + ":" + id).toList.toList match {
      case s :: _ => Full(s)
      case Nil => Empty
    }
  }

  def getVertex(id: String): Box[Vertex] = {
    db.getVertex(id) match {
      case null => Empty
      case some => Full(some)
    }
  }


  def findVOrCreateById(source: String, id: String): Vertex = {

    G(startPoint).out(source + ":" + id).toList.toList match {
      case Nil => createV(source, id)
      case v :: _ => v
    }

  }

  def end = free()

  def all = new GremlinScalaPipeline().start(startPoint).out


}
